package com.smart.community.property.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.smart.community.commons.entity.property.PropertyCompanyCommunity;
import com.smart.community.commons.result.Result;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.feign.region.dto.HouseholdInfoDTO;
import com.smart.community.feign.region.service.RegionDataFeignService;
import com.smart.community.property.service.DataScopeService;
import com.smart.community.property.service.IPropertyCompanyCommunityService;
import com.smart.community.property.service.IPropertyCompanyStatisticsService;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 物业公司统计服务实现类
 * 提供高性能的物业公司数据统计功能，包含缓存策略和异步处理
 * 严格遵循Java后端SpringBoot代码开发规范，支持数据权限控制和生产环境高标准
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 * @version 3.0.0 - 生产环境优化版本，增强数据权限控制、异常处理和性能优化
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PropertyCompanyStatisticsServiceImpl implements IPropertyCompanyStatisticsService {

    private final IPropertyCompanyCommunityService propertyCompanyCommunityService;
    private final RegionDataFeignService regionDataFeignClient;
    private final DataScopeService dataScopeService;
    private final Executor asyncExecutor;

    // 默认房户面积（平方米），当房户面积字段为NULL时使用此值
    private static final BigDecimal DEFAULT_HOUSEHOLD_AREA = new BigDecimal("89.50");

    @Override
    @Cacheable(value = "property:totalServiceArea", key = "#propertyCompanyId", unless = "#result == null")
    public Result<BigDecimal> getTotalServiceArea(Long propertyCompanyId) throws Exception {
        long startTime = System.currentTimeMillis();
        String operation = "获取物业公司总服务面积";
        
        try {
            // 1. 参数验证
            validatePropertyCompanyId(propertyCompanyId);
            
            // 2. 数据权限验证
            validateDataPermission(propertyCompanyId);
            
            log.info("{}开始，物业公司ID：{}", operation, propertyCompanyId);
            
            // 3. 获取物业公司关联的社区ID列表
            List<Long> communityIds = getCommunityIdsByPropertyCompany(propertyCompanyId);
            if (CollectionUtils.isEmpty(communityIds)) {
                log.info("物业公司{}没有关联的社区，总服务面积为0", propertyCompanyId);
                BigDecimal zeroResult = BigDecimal.ZERO;
                logPerformanceMetrics(operation, propertyCompanyId, startTime, zeroResult);
                return Result.success(zeroResult);
            }

            // 4. 按照业务逻辑：社区→楼栋→单元→房户→面积累加
            BigDecimal totalArea = calculateTotalServiceArea(communityIds);
            BigDecimal finalResult = totalArea != null ? totalArea : BigDecimal.ZERO;
            
            // 5. 性能监控
            logPerformanceMetrics(operation, propertyCompanyId, startTime, finalResult);
            
            return Result.success(finalResult);
            
        } catch (Exception e) {
            return handleException(operation, propertyCompanyId, e, startTime);
        }
    }

    @Override
    public Result<Long> getServiceCommunityCount(Long propertyCompanyId) throws Exception {
        long startTime = System.currentTimeMillis();
        String operation = "获取物业公司服务社区数量";
        
        try {
            // 1. 参数验证
            validatePropertyCompanyId(propertyCompanyId);
            
            // 2. 数据权限验证
            validateDataPermission(propertyCompanyId);
            
            log.info("{}开始，物业公司ID：{}", operation, propertyCompanyId);
            
            // 3. 获取物业公司关联的社区数量
            List<PropertyCompanyCommunity> communities = propertyCompanyCommunityService
                    .getPropertyCompanyCommunities(propertyCompanyId);
            
            Long count = communities != null ? (long) communities.size() : 0L;
            
            // 4. 性能监控
            logPerformanceMetrics(operation, propertyCompanyId, startTime, count);
            
            return Result.success(count);
            
        } catch (Exception e) {
            return handleException(operation, propertyCompanyId, e, startTime);
        }
    }

    @Override
    public Result<Long> getServiceHouseholdCount(Long propertyCompanyId) throws Exception {
        long startTime = System.currentTimeMillis();
        String operation = "获取物业公司服务户数";
        
        try {
            // 1. 参数验证
            validatePropertyCompanyId(propertyCompanyId);
            
            // 2. 数据权限验证
            validateDataPermission(propertyCompanyId);
            
            log.info("{}开始，物业公司ID：{}", operation, propertyCompanyId);
            
            // 3. 获取物业公司关联的社区ID列表
            List<Long> communityIds = getCommunityIdsByPropertyCompany(propertyCompanyId);
            if (CollectionUtils.isEmpty(communityIds)) {
                log.info("物业公司{}没有关联的社区，服务户数为0", propertyCompanyId);
                Long zeroResult = 0L;
                logPerformanceMetrics(operation, propertyCompanyId, startTime, zeroResult);
                return Result.success(zeroResult);
            }

            // 4. 按照业务逻辑：社区→楼栋→单元→房户→计算数量
            Long householdCount = calculateServiceHouseholdCount(communityIds);
            Long finalResult = householdCount != null ? householdCount : 0L;
            
            // 5. 性能监控
            logPerformanceMetrics(operation, propertyCompanyId, startTime, finalResult);
            
            return Result.success(finalResult);
            
        } catch (Exception e) {
            return handleException(operation, propertyCompanyId, e, startTime);
        }
    }

    @Override
    @Cacheable(value = "property:comprehensiveStats", key = "#propertyCompanyId", unless = "#result == null")
    public Result<Map<String, Object>> getComprehensiveStatistics(Long propertyCompanyId) throws Exception {
        long startTime = System.currentTimeMillis();
        String operation = "获取物业公司综合统计信息";
        
        try {
            // 1. 参数验证
            validatePropertyCompanyId(propertyCompanyId);
            
            // 2. 数据权限验证
            validateDataPermission(propertyCompanyId);
            
            log.info("{}开始，物业公司ID：{}", operation, propertyCompanyId);
            
            // 3. 获取物业公司关联的社区ID列表
            List<Long> communityIds = getCommunityIdsByPropertyCompany(propertyCompanyId);
            if (CollectionUtils.isEmpty(communityIds)) {
                log.info("物业公司{}没有关联的社区，返回默认统计信息", propertyCompanyId);
                Map<String, Object> defaultStats = createDefaultStatistics(propertyCompanyId);
                logPerformanceMetrics(operation, propertyCompanyId, startTime, defaultStats);
                return Result.success(defaultStats);
            }

            // 4. 生产环境高标准：使用异步并行处理，提高性能
            CompletableFuture<BigDecimal> areaFuture = CompletableFuture
                    .supplyAsync(() -> {
                        try {
                            return calculateTotalServiceArea(communityIds);
                        } catch (Exception e) {
                            log.error("异步计算总服务面积异常", e);
                            return BigDecimal.ZERO;
                        }
                    }, asyncExecutor);
            
            CompletableFuture<Long> communityFuture = CompletableFuture
                    .supplyAsync(() -> {
                        try {
                            // 直接返回社区数量，避免重复查询
                            return (long) communityIds.size();
                        } catch (Exception e) {
                            log.error("异步计算服务社区数量异常", e);
                            return 0L;
                        }
                    }, asyncExecutor);
            
            CompletableFuture<Long> householdFuture = CompletableFuture
                    .supplyAsync(() -> {
                        try {
                            return calculateServiceHouseholdCount(communityIds);
                        } catch (Exception e) {
                            log.error("异步计算服务户数异常", e);
                            return 0L;
                        }
                    }, asyncExecutor);

            // 5. 等待所有异步任务完成
            CompletableFuture.allOf(areaFuture, communityFuture, householdFuture).join();
            
            // 6. 组装统计结果
            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalServiceArea", areaFuture.get());
            statistics.put("serviceCommunityCount", communityFuture.get());
            statistics.put("serviceHouseholdCount", householdFuture.get());
            statistics.put("propertyCompanyId", propertyCompanyId);
            statistics.put("statisticsTime", System.currentTimeMillis());
            
            // 7. 性能监控
            logPerformanceMetrics(operation, propertyCompanyId, startTime, statistics);
            
            return Result.success(statistics);
            
        } catch (Exception e) {
            return handleException(operation, propertyCompanyId, e, startTime);
        }
    }
    
    /**
     * 创建默认统计信息
     * 当物业公司没有关联社区时使用
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 默认统计信息
     */
    private Map<String, Object> createDefaultStatistics(Long propertyCompanyId) {
        Map<String, Object> defaultStats = new HashMap<>();
        defaultStats.put("totalServiceArea", BigDecimal.ZERO);
        defaultStats.put("serviceCommunityCount", 0L);
        defaultStats.put("serviceHouseholdCount", 0L);
        defaultStats.put("propertyCompanyId", propertyCompanyId);
        defaultStats.put("statisticsTime", System.currentTimeMillis());
        return defaultStats;
    }

    @Override
    public Result<Boolean> refreshStatisticsCache(Long propertyCompanyId) throws Exception {
        long startTime = System.currentTimeMillis();
        String operation = "刷新物业公司统计缓存";
        
        try {
            // 1. 参数验证
            validatePropertyCompanyId(propertyCompanyId);
            
            // 2. 数据权限验证
            validateDataPermission(propertyCompanyId);
            
            log.info("{}开始，物业公司ID：{}", operation, propertyCompanyId);
            
            // 3. 缓存清除逻辑（已移除缓存注解，此方法保留用于未来扩展）
            
            Boolean result = true;
            
            // 4. 性能监控
            logPerformanceMetrics(operation, propertyCompanyId, startTime, result);
            
            return Result.success(result);
            
        } catch (Exception e) {
            return handleException(operation, propertyCompanyId, e, startTime);
        }
    }

    /**
     * 根据物业公司ID获取关联的社区ID列表
     * 
     * @param propertyCompanyId 物业公司ID
     * @return 社区ID列表
     * @throws Exception 获取失败时抛出异常
     */
    private List<Long> getCommunityIdsByPropertyCompany(Long propertyCompanyId) throws Exception {
        List<PropertyCompanyCommunity> communities = propertyCompanyCommunityService
                .getPropertyCompanyCommunities(propertyCompanyId);
        
        if (CollectionUtils.isEmpty(communities)) {
            return new ArrayList<>();
        }
        
        return communities.stream()
                .map(PropertyCompanyCommunity::getCommunityId)
                .collect(Collectors.toList());
    }

    /**
     * 优化后的总服务面积计算逻辑：使用两步查询方式
     * 1. 根据社区ID获取房户ID列表
     * 2. 根据房户ID列表获取房户详细信息
     * 避免复杂的多层查询（社区→楼栋→单元→房户），提升性能
     * 
     * @param communityIds 社区ID列表
     * @return 总服务面积
     * @throws Exception 获取失败时抛出异常
     */
    private BigDecimal calculateTotalServiceArea(List<Long> communityIds) throws Exception {
        BigDecimal totalArea = BigDecimal.ZERO;
        
        try {
            // 第一步：根据社区ID获取房户ID列表
            List<Long> householdIds = regionDataFeignClient.getHouseholdIdsByCommunityIds(communityIds);
            log.debug("社区{}下查询到房户ID数量：{}", communityIds, householdIds != null ? householdIds.size() : 0);
            
            if (CollectionUtils.isEmpty(householdIds)) {
                log.info("社区{}下没有房户数据，总服务面积为0", communityIds);
                return totalArea;
            }

            // 第二步：根据房户ID列表获取房户详细信息
            List<HouseholdInfoDTO> households = regionDataFeignClient.getHouseholdsByIds(householdIds);
            log.debug("获取到房户详细信息：{}", households != null ? households.size() : 0);
            
            if (households != null && !households.isEmpty()) {
                totalArea = households.stream()
                        .map(household -> {
                            if (household != null && household.getArea() != null) {
                                try {
                                    return BigDecimal.valueOf(household.getArea());
                                } catch (NumberFormatException e) {
                                    log.warn("房户{}面积格式错误：{}，使用默认面积{}平方米", household.getId(), household.getArea(), DEFAULT_HOUSEHOLD_AREA);
                                    return DEFAULT_HOUSEHOLD_AREA;
                                }
                            } else {
                                // 当面积为NULL时，使用默认面积
                                log.debug("房户{}面积字段为NULL，使用默认面积{}平方米", household != null ? household.getId() : "unknown", DEFAULT_HOUSEHOLD_AREA);
                                return DEFAULT_HOUSEHOLD_AREA;
                            }
                        })
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                
                log.info("房户面积累加完成，总服务面积：{}平方米", totalArea);
            } else {
                log.info("社区{}下没有房户详细信息，总服务面积为0", communityIds);
            }
        } catch (Exception e) {
            log.error("计算总服务面积异常", e);
            throw e;
        }
        
        return totalArea;
    }

    /**
     * 优化后的服务户数计算逻辑：使用两步查询方式
     * 1. 根据社区ID获取房户ID列表
     * 2. 直接返回房户ID数量，避免获取详细信息
     * 避免复杂的多层查询（社区→楼栋→单元→房户），提升性能
     * 
     * @param communityIds 社区ID列表
     * @return 总服务户数
     * @throws Exception 获取失败时抛出异常
     */
    private Long calculateServiceHouseholdCount(List<Long> communityIds) throws Exception {
        Long householdCount = 0L;
        
        try {
            // 直接根据社区ID获取房户ID列表，避免复杂的多层查询
            // 这样可以减少Feign调用次数，提升性能
            List<Long> householdIds = regionDataFeignClient.getHouseholdIdsByCommunityIds(communityIds);
            log.debug("社区{}下查询到房户ID数量：{}", communityIds, householdIds != null ? householdIds.size() : 0);
            
            if (householdIds != null && !householdIds.isEmpty()) {
                householdCount = (long) householdIds.size();
                log.info("房户数量统计完成，总服务户数：{}户", householdCount);
            } else {
                log.info("社区{}下没有房户数据，服务户数为0", communityIds);
            }
            
        } catch (Exception e) {
            log.error("计算服务户数异常", e);
            throw e;
        }
        
        return householdCount;
    }
    
    /**
     * 参数验证工具方法
     * 严格遵循Java后端SpringBoot代码开发规范中的参数验证要求
     * 
     * @param propertyCompanyId 物业公司ID
     * @throws IllegalArgumentException 参数无效时抛出异常
     */
    private void validatePropertyCompanyId(Long propertyCompanyId) {
        if (propertyCompanyId == null) {
            log.error("物业公司ID不能为空");
            throw new IllegalArgumentException("物业公司ID不能为空");
        }
        if (propertyCompanyId <= 0) {
            log.error("物业公司ID必须大于0，当前值：{}", propertyCompanyId);
            throw new IllegalArgumentException("物业公司ID必须大于0");
        }
    }
    
    /**
     * 数据权限验证工具方法
     * 使用DataScopeFeign验证用户是否有权限访问指定物业公司的数据
     * 严格遵循数据权限设计文档的要求
     * 
     * @param propertyCompanyId 物业公司ID
     * @throws SecurityException 权限不足时抛出异常
     */
    private void validateDataPermission(Long propertyCompanyId) {
        try {
            // 获取当前用户ID（这里需要根据实际的安全上下文获取）
            // 注意：在实际应用中，应该从SecurityContext或其他安全框架中获取当前用户ID
            Long currentUserId = SecurityUtils.getCurrentUserId();
            
            if (currentUserId == null) {
                log.warn("无法获取当前用户ID，跳过权限验证");
                return; // 在开发环境或测试环境中可以跳过权限验证
            }
            
            // 检查用户是否有物业公司权限
            try {
                boolean hasPermission = dataScopeService.hasPropertyCompanyPermission(currentUserId, propertyCompanyId);
                if (!hasPermission) {
                    log.warn("用户{}没有权限访问物业公司{}的统计数据", currentUserId, propertyCompanyId);
                    throw new SecurityException("您没有权限访问该物业公司的统计数据");
                }
            } catch (Exception e) {
                log.error("检查用户物业公司权限失败，用户ID：{}，物业公司ID：{}", currentUserId, propertyCompanyId, e);
                throw new SecurityException("权限验证失败：" + e.getMessage());
            }
            log.debug("用户{}权限验证通过，可以访问物业公司{}的统计数据", currentUserId, propertyCompanyId);
        } catch (Exception e) {
            log.error("数据权限验证异常，物业公司ID：{}", propertyCompanyId, e);
            if (e instanceof SecurityException) {
                throw e;
            }
            throw new SecurityException("数据权限验证失败：" + e.getMessage());
        }
    }
    
    /**
     * 统一的异常处理工具方法
     * 严格遵循Java后端SpringBoot代码开发规范中的异常处理要求
     * 
     * @param operation 操作描述
     * @param propertyCompanyId 物业公司ID
     * @param e 异常对象
     * @param startTime 开始时间
     * @return 失败结果
     */
    @SuppressWarnings("unchecked")
    private <T> Result<T> handleException(String operation, Long propertyCompanyId, Exception e, long startTime) {
        long responseTime = System.currentTimeMillis() - startTime;
        String errorMessage = String.format("%s失败，物业公司ID：%s，耗时：%dms", operation, propertyCompanyId, responseTime);
        
        log.error(errorMessage, e);
        
        // 根据异常类型返回不同的错误信息
        if (e instanceof IllegalArgumentException) {
            return (Result<T>) Result.fail("参数错误：" + e.getMessage());
        } else if (e instanceof SecurityException) {
            return (Result<T>) Result.fail("权限不足：" + e.getMessage());
        } else {
            return (Result<T>) Result.fail(operation + "失败：" + e.getMessage());
        }
    }
    
    /**
     * 性能监控工具方法
     * 记录方法执行时间和性能指标，用于生产环境监控
     * 
     * @param operation 操作描述
     * @param propertyCompanyId 物业公司ID
     * @param startTime 开始时间
     * @param result 执行结果
     */
    private void logPerformanceMetrics(String operation, Long propertyCompanyId, long startTime, Object result) {
        long responseTime = System.currentTimeMillis() - startTime;
        
        // 性能警告阈值（毫秒）
        long warningThreshold = 1000L; // 1秒
        long errorThreshold = 3000L;   // 3秒
        
        if (responseTime > errorThreshold) {
            log.error("{}性能异常，物业公司ID：{}，耗时：{}ms，结果：{}", operation, propertyCompanyId, responseTime, result);
        } else if (responseTime > warningThreshold) {
            log.warn("{}性能警告，物业公司ID：{}，耗时：{}ms，结果：{}", operation, propertyCompanyId, responseTime, result);
        } else {
            log.info("{}执行成功，物业公司ID：{}，耗时：{}ms，结果：{}", operation, propertyCompanyId, responseTime, result);
        }
    }
}
